const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const tsImportPluginFactory = require("ts-import-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const webpack = require("webpack");
const merge = require("webpack-merge");

let isDev = process.env.NODE_ENV == "development" ? true : false;
const dllPath = path.resolve(__dirname, "dist/dll");

const devConfig = {
  mode: "development",
  devtool: "source-map",
  devServer: {
    hot: true,
    host:"0.0.0.0",
    port:12080,
    contentBase: path.join(__dirname, "dist"),
    writeToDisk:true,//写入硬盘
    historyApiFallback: {
      index: "/index.html", //browserHistory的时候，刷新会报404,自动重定向index.html
      verbose:true,
    },  
    proxy: {
      "/api": "http://localhost:12081"
    }
  },
  plugins: [
    // new BundleAnalyzerPlugin()
  ],
};

const prodConfig = {
  mode: "production",
  optimization: {
    minimize: true,
    minimizer: [
      new TerserJSPlugin({
        cache: true,
        parallel: true,
      }),
      new OptimizeCSSAssetsPlugin({}),
    ],
  },
  plugins:[

  ]
};

const cssLoaders = [
  {
    loader: MiniCssExtractPlugin.loader,
    options: {
      esModule: true,
    },
  },
  {
    loader: "css-loader",
    options: {
      importLoaders: 0, //样式里面不要再引入样式文件了
    },
  },
  {
    loader: "postcss-loader",
    options: {
      plugins: [require("autoprefixer")],
    },
  },
  {
    loader: "px2rem-loader",
    options: {
      remUnit: 75, //一个rem代表75px
      remPrecesion: 8, //计算精度保留8位小数
    },
  },
];

const getStyleLoaders = (isUsePostcss,cssOptions, preProcessor) => {
  const loaders = [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        esModule: true,
      },
    },
    {
      loader: 'css-loader',
      options: cssOptions,
    },
  ];
  isUsePostcss && loaders.push({
    loader: "postcss-loader",
    options: {
      plugins:[require('postcss-preset-env')()]
    },
  });
  preProcessor && loaders.push(preProcessor)
  return loaders;
};

const splitChunks = {
  chunks: "all", //默认作用于异步chunk，值为all/initial/async
  minSize: 30000, //默认值是30kb,代码块的最小尺寸
  minChunks: 1, //被多少模块共享,在分割之前模块的被引用次数
  maxAsyncRequests: 5, //按需加载最大并行请求数量
  maxInitialRequests: 3, //一个入口的最大并行请求数量
  name: true, //打包后的名称，默认是chunk的名字通过分隔符（默认是～）分隔开，如vendor~
  automaticNameDelimiter: "~", //默认webpack将会使用入口名和代码块的名称生成命名,比如 'vendors~main.js'
  cacheGroups: {
    //设置缓存组用来抽取满足不同规则的chunk,下面以生成common为例
    vendors: {
      test: /node_modules/, //条件
      priority: -10 ///优先级，一个chunk很可能满足多个缓存组，会被抽取到优先级高的缓存组中,为了能够让自定义缓存组有更高的优先级(默认0),默认缓存组的priority属性为负值.
    },
    commons: {
      minSize: 0, //最小提取字节数
      minChunks: 2, //最少被几个chunk引用
      priority: -20,
      reuseExistingChunk: true //    如果该chunk中引用了已经被抽取的chunk，直接引用该chunk，不会重复打包代码
    }
  },
};

const config = {
  entry: {
    main: "./src/index.tsx",
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].js",
    chunkFilename: '[name].[hash:8].js',//动态import文件名
    publicPath: "/",
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
      "~": path.resolve(__dirname, "node_modules"),
    },
    extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
  },
  optimization: {
    splitChunks,
  },
  module: {
    rules: [
      {
        test: /\.(j|t)sx?$/, //js处理入口
        exclude: /node_modules/,
        use:[{
          loader: "ts-loader",
          options: {
            //设置自定义转换器,TypeScript 可以将 TS 源码编译成 JS 代码，自定义转换器插件则可以让你定制生成的代码。比如删掉代码里的注释、改变变量的名字、将类转换为函数等等
            transpileOnly: true,
            //ts-import-plugin是为了按需引入antd
            getCustomTransformers: () => ({
              before: [
                tsImportPluginFactory({
                  libraryName: "antd",
                  libraryDirectory: "es",
                  style: "css",
                }),
              ],
            }),
            compilerOptions: {
              module: "es2015",
            },
          },
        }]
      },
      {
        test: /\.css$/, // css处理入口
        exclude: /node_modules/,
        use: [...cssLoaders],
      },
      {
        test: /\.css$/, // css处理入口
        include: /node_modules/, // antd等三方样式处理入口
        use: getStyleLoaders(false, {
          importLoaders: 1
        })
      },
      {
        test: /\.less$/, // 处理less
        exclude: /node_modules/,
        use: [...cssLoaders, "less-loader"],
      },
      {
        test: /\.(jpg|png|gif|svg|jpeg)$/, //处理图片,把图片打包到输出目录中
        use: {
          loader: "url-loader",
          options: {
            limit: 8192,
            outputPath: "./assets/images",
            publicPath: "./assets/images",
            name: "[name].[ext]",
          },
        },
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: ["*.js", "*.html", "*.css", "*.map", "*.json"],
    }),
    new MiniCssExtractPlugin({
      filename: "[name].[contentHash:8].css",
      chunkFilename: "[name].[contentHash:8].css",
      ignoreOrder: true, //  启用以删除有关顺序冲突的警告
    }),
    //热更新插件
    new webpack.HotModuleReplacementPlugin(),
    new CopyPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, "src/public"),
          to: path.resolve(__dirname, "dist"),
          toType: "dir",
          globOptions:{
            ignore:['**/config/**']
          }
        },
      ],
    }),
    new HtmlWebpackPlugin({
      template: "./src/index.html", //以此文件作为模板拼入打包后的文件并输出到目标目录中
    }),
    new webpack.DllReferencePlugin({
      manifest: require(path.resolve(dllPath, "react_manifest.json")),
    }),
  ],
  performance: {
    maxAssetSize: 1 * 1024 * 1024, //默认值：250000 (bytes)
    maxEntrypointSize: 1 * 1024 * 1024,
  },
  //  stats: isDev ? "verbose" : "minimal", //日志 minimal normal verbose
};

// module.exports = isDev
//   ? smp.wrap(merge(config, devConfig))
//   : smp.wrap(merge(config, prodConfig));

module.exports = isDev?merge(config, devConfig):merge(config, prodConfig);
